package main

import (
	"fmt"
	"net"
	"os"
	"os/signal"
	"syscall"

	"github.com/namsral/flag"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/health"
	healthpb "google.golang.org/grpc/health/grpc_health_v1"

	"mxshop_srvs/inventory_srv/dao/mysql"
	"mxshop_srvs/inventory_srv/dao/redis"
	"mxshop_srvs/inventory_srv/handler"
	"mxshop_srvs/inventory_srv/logger"
	proto "mxshop_srvs/inventory_srv/proto/gen/v1"
	"mxshop_srvs/inventory_srv/setting"
	"mxshop_srvs/inventory_srv/utils"
	"mxshop_srvs/inventory_srv/utils/consul"
)

var IP = flag.String("ip", "0.0.0.0", "ip地址")
var Port = flag.Int("port", 0, "端口号")

func main() {
	flag.Parse()

	// init config
	setting.Init()

	// init logger
	logger.Init()
	defer func(l *zap.Logger) {
		_ = l.Sync()
	}(zap.L())

	// init mysql
	db, err := mysql.Init()
	if err != nil {
		panic(err)
	}

	// init redis
	rdb, err := redis.Init()
	if err != nil {
		panic(err)
	}

	if *Port == 0 {
		port, err := utils.GetFreePort()
		if err != nil {
			zap.L().Fatal("cannot get free port", zap.Error(err))
		}
		*Port = port
	}

	lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", *IP, *Port))
	if err != nil {
		zap.L().Fatal("goods service cannot listen", zap.Error(err))
	}

	s := grpc.NewServer()
	proto.RegisterInventoryServer(s, handler.NewService(
		mysql.NewGorm(db),
		redis.NewRedis(rdb),
	))

	// gRPC健康检查
	healthpb.RegisterHealthServer(s, health.NewServer())

	// 服务注册
	consulConf := setting.Conf.ConsulConfig
	c, err := consul.NewConsul(fmt.Sprintf("%s:%d", consulConf.Host, consulConf.Port))
	if err != nil {
		zap.L().Fatal("cannot create consul api client", zap.Error(err))
	}

	b, err := utils.GetOutboundIP()
	if err != nil {
		zap.L().Fatal("get out bound ip failed", zap.Error(err))
	}

	ip := b.String()
	name := consulConf.Name
	tags := append(consulConf.Tags, setting.Conf.Name)

	err = c.RegisterService(name, ip, *Port, tags)
	if err != nil {
		zap.L().Fatal("register to consul failed", zap.Error(err))
	}

	// 启动服务
	go func() {
		zap.L().Info("server started", zap.String(setting.Conf.Name, fmt.Sprintf("%s:%d", *IP, *Port)))
		err = s.Serve(lis)
		if err != nil {
			zap.L().Fatal("failed to start grpc:", zap.Error(err))
			return
		}
	}()

	quitChan := make(chan os.Signal, 1) // 定义一个通道 当程序退出时从consul中注销服务
	// SIGTERM: kill命令 = kill -15 命令
	// SIGINT: ctrl+c
	// SIGKILL: kill -9 命令
	signal.Notify(quitChan, syscall.SIGTERM, syscall.SIGINT)
	<-quitChan // hang住
	// 程序退出时从consul中注销服务
	serviceID := fmt.Sprintf("%s-%s-%d", name, ip, *Port)
	err = c.DeregisterService(serviceID)
	if err != nil {
		zap.L().Error("cannot deregister from consul", zap.String("service_id", serviceID), zap.Error(err))
	}
}
